﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Media;

namespace Mahanet.Abyss.PathCalculation
{
	public class SingleDataManager
	{
		#region Fields

		private IDataDisplayer m_DataDisplayer;
		private IDataGenerator<double, double> m_DataGenerator;
		private Dictionary<int, IPathOracle<double, double>> m_IdToApproximatorDictionary
						= new Dictionary<int,IPathOracle<double,double>>();

		#endregion

		#region C'tor

		public SingleDataManager(IDataDisplayer dataDisplayer, IDataGenerator<double, double> dataGenerator)
		{
			m_DataDisplayer = dataDisplayer;

			m_DataGenerator = dataGenerator;

			m_DataGenerator.DataGenerated += m_DataGenerator_DataGenerated;
		}

		#endregion

		#region Public Methods

		public void DisplayDataSeries(int dataSeriesUniqueId)
		{
			IPathOracle<double, double> approximator;
			if (!m_IdToApproximatorDictionary.TryGetValue(dataSeriesUniqueId, out approximator))
			{
				return;
			}

			approximator.GenerateApproximation();

			m_DataDisplayer.AddFunction("Approximations", t => new Coordinate2D(t, approximator.Approximation(t)),
										GetColorByCertainty(approximator.GetCertainty()),
										2);

			m_DataDisplayer.DisplayStatus(string.Format("Certainty: {0}", approximator.GetCertainty()));
		}

		#endregion

		#region Event Handlers

		private void m_DataGenerator_DataGenerated(DataPoint<double, double> dataPoint, int dataSeriesUniqueId)
		{
			IPathOracle<double, double> approximator;
			if (!m_IdToApproximatorDictionary.TryGetValue(dataSeriesUniqueId, out approximator))
			{
				approximator = new LeastSquaresLinearSinglePathOracle();
				m_IdToApproximatorDictionary.Add(dataSeriesUniqueId, approximator);
			}

			approximator.AddPointData(dataPoint);

			m_DataDisplayer.AddDataPoint("GeneratedData", dataPoint.Paramter, dataPoint.Value);
		}

		private Color GetColorByCertainty(double p)
		{
			p = Math.Pow(p, 2);
			Color certainColor = Colors.DarkGreen;
			Color uncertainColor = Colors.LightYellow;

			var red = uncertainColor.R + (int)((certainColor.R - uncertainColor.R) * p);
			var green = uncertainColor.G + (int)((certainColor.G - uncertainColor.G) * p);
			var blue = uncertainColor.B + (int)((certainColor.B - uncertainColor.B) * p);

			return Color.FromRgb((byte)red, (byte)green, (byte)blue);
		}

		#endregion
	}
}
